<?php defined('SYSPATH') or die('No direct script access.');

/**
 * @example 三种情况
 *
 */

if (!defined('MB_ENABLE'))
	define('MB_ENABLE',function_exists('mb_convert_encoding'));
abstract class Kohana_Validate {

	const SUB_OK = 0;
	const SUB_EXP = 1;
	const SUB_LEN = 2;
	const SUB_MLEN = 4;
	const SUB_RAN = 8;
	const SUB_REQ = 16;
	const SUB_INVALID_PARAM = 32;
	const SUB_GREATER = 64;
	const SUB_BANNED = 128;
	const SUB_NO_ZERO = 256;
	protected $_config = array();
	protected $_patterns = array();
	public function __construct()
	{
		$this->_config = (array)Kohana::$config->load('validate');
		$this->_patterns = array (
			'date' => '(1[1-9]\d{2}|20\d{2}|2100)-([0-1]?[1-9]|1[0-2])-([0-2]?[1-9]|3[0-1]|[1-2]0)',//1988-1-1 / 1988-01-01
			'time' => '([0-1]?\d|2[0-3]):([0-5]?\d)(:([0-5]?\d))?', //1:1:23 / 01:01:23
			'datetime' => '(1[1-9]\d{2}|20\d{2}|2100)-([0-1]?[1-9]|1[0-2])-([0-2]?[1-9]|3[0-1]|[1-2]0)(\s([0-1]?\d|2[0-3]):([0-5]?\d)(:([0-5]?\d))?)?', //可以不输入时间
			'url' => '(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(([a-z]|\d|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])([a-z]|\d|-|\.|_|~|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])*([a-z]|\d|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])))\.)+(([a-z]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(([a-z]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])([a-z]|\d|-|\.|_|~|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])*([a-z]|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)|[\x{E000}-\x{F8FF}]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\x{00A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}])|(%[\da-f]{2})|[!\$&\'\(\)\*\+,;=]|:|@)|\/|\?)*)?',
			'email' => '[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*',
		);

	}

	public static function &instance() {
		static $object;
		if(empty($object)) {
			$object = new Validate();
		}
		return $object;
	}
	/**
	 * 传递keys的数组，从POST中获取对应的字段，并做验证
	 *
	 * @param mixed $keys 字段集合，可以为[*]，代表此Table下的所有字段；可以为数组；可以为字符串，字符串以[,][;][|](逗号、分号、中竖线)分隔
	 * @param string $table_name 字段所在的表名
	  * @param string $method 数据取自POST/GET
	 * @return array 返回从POST中取出的字段值，以及验证之后的错误信息
	 */
	public function get_post_data($keys, $table_name, $method = 'post')
	{
		$_fields = $this->_filter_line($keys,$table_name);
		$method = in_array(strtolower($method),array('post','query','get','param')) ? strtolower($method) : 'post'; $method == 'get' && $method = 'query';
		$data = array();
		$error = array();
		if (!empty($_fields))
		{
			$request = Request::initial();
			$keys = array(
				'string' => array('str','string'),
				'bool' => array('bool','boolean'),
				'time' => array('timestamp', 'timetick', 'daytick'),
				'number' => array('int', 'integer', 'long', 'real', 'digits', 'number', 'float', 'double', 'type', 'timestamp', 'timetick','daytick'),
			);
			foreach ($_fields as $key => $line) { //2

				$exp = $line['verify'];
				$multi = $line['multi'];
				$greater = $line['greater'];
				$type = !empty($line['type']) ? $line['type'] : $key;

				$value = $request->$method($key);

				!isset($value) && $value = NULL;
				$multi && empty($value) && $value = array(); //多选，给一个默认值
				
				$data[$key] = $value;

				if (is_null($value) && $method != 'query') //没有传递值过来，则表示缺少该字段
				{
					$error[$key] = $this->_get_error(Validate::SUB_INVALID_PARAM, $line);
				}
				elseif ($multi && empty($value)) //多选为空的情况
				{
					if ($exp['required'])
						$error[$key] = $this->_get_error(Validate::SUB_REQ, $line);
				}
				else
				{

					$_values = to_array($value, FALSE);

					//判断多选的个数问题
					if ($multi)
					{
						$count = count($_values);
						if ($this->_check_number($count, $exp['minlength'], $exp['maxlength']) != Validate::SUB_OK) {
							$error[$key] = $this->_get_error(Validate::SUB_MLEN, $line);
							continue;
						}
					}

					//验证所有字段
					foreach($_values as $k => $v) //1
					{
						in_array($exp['exp'], $keys['string']) && $v = trim($v); //去掉前后空格
						in_array($exp['exp'], $keys['bool']) && $v = boolval($v, TRUE); //严格的转化为BOOL类型
						//$exp['exp'] == 'type' && $v = intval($v); //将空白时间转化为0
						in_array($exp['exp'], $keys['time']) && empty($v) && $v = 0; //将空白时间转化为0
						in_array($exp['exp'], $keys['time']) && !empty($v) && !is_numeric($v) && $v = strtotime($v); //将时间转化为时间戳
						$exp['exp'] == 'timetick' && !empty($v) && $v = timestamp_to_timetick($v); //将时间转化为timetick
						$exp['exp'] == 'daytick' && !empty($v) && $v = timestamp_to_daytick($v); //将时间转化为daytick
						is_string($v) && $v = str_replace(array("\r\n", "\r"), "\n", $v); //替换回车
						is_numeric($v) && in_array($exp['exp'], $keys['number']) && $v += 0; //转化成数字

						if ($v === '') //处理字符串为空
						{
							if ($exp['required'])
								$error[$key] = $this->_get_error(Validate::SUB_REQ, $line);
						} 
						elseif ($exp['exp'] == 'type' && $v === 0) //当TYPE为必选时，检查是否为0
						{
							if ($exp['required'])
								$error[$key] = $this->_get_error(Validate::SUB_REQ, $line);
						}
						elseif (in_array($exp['exp'], $keys['time']) && $v === FALSE) //时间格式有问题
						{
							$error[$key] = $this->_get_error(Validate::SUB_EXP, $line);
						}
						elseif (Validate::SUB_NO_ZERO === $exp['required'] && ($v === 0 || $v === '0')) //不能为零
						{
							$error[$key] = $this->_get_error(Validate::SUB_NO_ZERO, $line);
						}
						else //由于select/radio的value以及input中int、float可能会出现0的情况，所以不验证值为0
						{
							$_check = $this->_check($type, $exp, $v, $line['data']);
							if ($_check != Validate::SUB_OK)
							{
								$error[$key] = $this->_get_error($_check, $line);
								continue;
								//break 1;
							}
						}
						$_values[$k] = $v;
					}

					//判断GREATER
					if($greater && !$multi && count($_values) == 1) //必须不是多选的情况
					{ 
						$_v = $_values[0];
						if(isset($data[$greater]) && !empty($data[$greater]) && !empty($_v))
						{
							if ( $_v < $data[$greater]) 
							{
								$text2 = $_fields[$greater]['text'];
								$error[$key] = $this->_get_error(Validate::SUB_GREATER, $line, $text2);
								continue;
							}
						}
					}
					$data[$key] = is_array($value) ? $_values : array_shift($_values);
				}
			}
		}
		return array('data' => $data, 'error' => $error);
	}

	public function get_order_by($keys, $order_by_param)
	{
		$_order_array = array('ASC','DESC');
		$keys_array = _array_selector_subkey($keys);

		$original = $list = array();
		if (!empty($order_by_param))
		{
			foreach ($order_by_param as $key => $value) {
				if (!in_array($key, $keys_array))
					continue;
				$value = strtoupper($value);
				!in_array($value, $_order_array) && $value = 'ASC';
				$original[$key] = $value;
			}
		}
		foreach ($keys_array as $value) {
			$list[$value] = value_next($original[$value], $_order_array);
		}

		return compact('original', 'list');
	}

	/**
	 * 传递keys的数组，获取jQuery.validate中的参数
	 *
	 * @param mixed $keys 字段集合，可以为[*]，代表此Table下的所有字段；可以为数组；可以为字符串，字符串以[,][;][|](逗号、分号、中竖线)分隔
	 * @param string $table_name 字段所在的的表名
	 * @param string $prefix method方法名的前缀,如果一个页面有两个表单需要验证,需要设定此项以避免命名冲突
	 * @return array 返回jQuery.Validate的Script信息
	 */
	public function get_jquery($keys, $table_name, $prefix = '')
	{
		$_exps = $this->_filter_line($keys,$table_name);
		$_methods = array('url'=>'url', 'number'=>'float', 'digits'=>'int', 'email'=>'email', 'timestamp'=>'timestamp', 'timetick' => 'timetick'); //jQuery validate 默认有这些
		$result = array('rules'=>array(), 'messages'=>array(), 'methods'=>&$_methods, 'texts'=>array(), 'ansi'=>array());
		if (empty($_exps))
			return $result;

		$prefix .= 'method_';
		foreach ($_exps as $key => $line)
		{
			$exp = $line['verify'];
			$jquery = array('required'=>$exp['required'] ? TRUE : FALSE);

			!empty($line['remote']) && $jquery['remote'] = $line['remote'];
			//大小/长度限制
			$postfix = '';
			!is_null($exp['minlength']) && $jquery['minlength'] = $exp['minlength'];
			!is_null($exp['maxlength']) && $jquery['maxlength'] = $exp['maxlength'];
			!is_null($exp['min']) && $jquery['min'] = $exp['min'];
			!is_null($exp['max']) && $jquery['max'] = $exp['max'];

			//重置某些正则
			switch ($exp['exp']) { //jQuery validate的date验证很不严格,这里重新设置一个表达式
				case 'date': case 'time': case 'datetime':
					$exp['exp'] = $this->_patterns[($exp['exp'])];
					break;
				case 'bool':
				case 'boolean':
					$exp['exp'] = '(true|false)';
					break;
				case 'timestamp': //没办法判断大小
				case 'timetick':
				case 'daytick':
					//$exp['exp'] = 'string';//$this->_patterns['datetime']; //验证类与WdatePicker产生冲突，验证会卡死
					unset($jquery['min'],$jquery['max']);	
					break;	
			}
			//新建规则
			if (!in_array($exp['exp'],array('string','str','text','type'))) {
				$name = array_search($exp['exp'],$_methods);
				if ($name === FALSE) { //new method
					$name = $prefix.count($_methods);
					switch ($exp['exp']) {
						case 'data':
						case 'array':
							//由于preg_quot会替换|,所以只能手写替换代码了T_T
							//$_methods[$name] = '('.str_replace(array('\\',' ','	',"\r","\n",'(',')','^','$','.','*','+','?'), array('\\\\','\s','\t','\r','\n','\(','\)','\^','\$','\.','\*','\+','\?'), implode('|', $line['data'])).')';
							$_methods[$name] = '('.implode('|', array_map('preg_quote', $line['data'])).')';
							break;
						case 'digits':
							$name = $exp['exp'];
							break;
						case 'number':
						case 'real':
						case 'double':
							$name = 'number';
							break;
						default:
							$_methods[$name] = $exp['exp'];
							break;
					}
				}
				$jquery[$name] = TRUE;
			}

			$keyname = $key.($line['multi'] ? '[]' : '');

			//配置Rules
			$result['rules'][$keyname] = $jquery;
			//读取错误消息
			$result['messages'][$keyname] = $this->_get_tips($table_name.'.'.$key, $line);
			if (empty($result['messages'][$keyname])) unset($result['messages'][$keyname]);
			$result['texts'][$keyname] = $line['text'];
			//汉字双字节设定
			if ($exp['char'] == 'ansi')
				$result['ansi'][$keyname] = TRUE;
		}//foreach
		return $result;
	}

	public function data_chunk($data,$table_name)
	{
		$_fields = $this->_read_fields_line($table_name);
		//print_r($_fields);
		$_data = array();
		foreach ($data as $key => $value) {
			$name = array_key_exists($key, $_fields) ? $_fields[$key]['parent'] : '';
			$_data[$name][$key] = $value;
		}
		return $_data;
	}

	public function get_fields($table_name)
	{
		$_fields = $this->_read_fields_line($table_name);

		return !empty($_fields) ? $_fields : array();
	}

	private function _filter_line($keys, $table_name)
	{
		$_fields = $this->_read_fields_line($table_name);
		$result = array();
		if (!empty($_fields))
		{
			if ($keys == '*')
				$keys = array_keys($_fields);
			elseif (!is_array($keys))
			{
				$keys = preg_replace('/\s*([,;])\s*/', '$1', $keys); //去掉这些分隔符前后的空格
				$keys = preg_split ('/[,;]+/', $keys, NULL, PREG_SPLIT_NO_EMPTY);
			}
			//填充默认数组
			$base = array_fill_keys($keys, array('verify' => $this->_parse_expression(NULL), 'text' => '', 'message' => '', 'multi' => FALSE, 'type' => '', 'data' => array(), 'remote' => '', 'greater' => NULL));
			$result = _extends($_fields, $base); //整合需要的项目
		}
		return $result;
	}

	private function _read_fields_line($table_name)
	{
		$table_names = array('*', '*', '*', 'verify,text,multi,greater,type,data,remote,message');
		$selector = preg_replace('/\s*([\\/,;])\s*/', '$1', $table_name); //去掉这些分隔符前后的空格
		$sp = preg_split('/[\\/]+/',$selector, NULL, PREG_SPLIT_NO_EMPTY);

		$selector = implode('/', $sp + $table_names); //前面的为准

		$_fields = array_selector($this->_config, $selector);

		$result = array();
		if (!empty($_fields)) {
			foreach ($_fields[($sp[0])] as $parent => $_field) {
				foreach($_field as $k => $v) {
					empty($v['text']) && $v['text'] = $k;
					$result[$k] = array('verify' => $this->_parse_expression($v['verify']), 'text' => $v['text'], 'message' => isset($v['message']) ? $v['message'] : NULL, 'multi' => isset($v['multi']) ? $v['multi'] : FALSE, 'type' => $v['type'] === TRUE ? $k : $v['type'], 'greater' => isset($v['greater']) ? $v['greater'] : NULL, 'data' => isset($v['data']) ? $v['data'] : array(), 'remote' => !empty($v['remote']) ? $v['remote'] : '', 'parent' => $parent);
				}
			}
		}
		return $result;
	}

	private function _check($key, $exp, $value, $data = array()) {
		$result = TRUE;
		switch($exp['exp']) {
			case 'string':
			case 'text':
				$result = $this->_check_string($value, $exp['minlength'], $exp['maxlength'], $exp['char']);
				break;
			case 'int':
			case 'integer':
			case 'digits':
			case 'number':
			case 'float':
			case 'real':
			case 'double':
			case 'timestamp':
			case 'timetick':
			case 'daytick':
				if ($value === 0 && !$exp['required'])//非必填情况下，默认可以为零
					$result = Validate::SUB_OK;
				else
					$result = $this->_check_number($value, $exp['min'], $exp['max'], $exp['minlength'], $exp['maxlength']);
				break;
			case 'bool':
			case 'boolean':
				$result = $this->_check_bool($value, $exp['required']);
				break;
			case 'email':
				$result = $this->_check_email($value, $exp['minlength'],$exp['maxlength']);
				break;
			case 'date':
				$result = $this->_check_date($value);
				break;
			case 'time':
				$result = $this->_check_time($value);
				break;
			case 'datetime':
				$result = $this->_check_datetime($value);
				break;
			case 'url':
				$result = $this->_check_url($value, $exp['minlength'], $exp['maxlength']);
				break;
			case 'type':
				$result = $this->_check_type($key, $value);
				break;
			case 'data':
			case 'array':
				$result = $this->_check_data($value, $data);
				break;
			default:
				$result = $this->_check_regexp($exp['exp'], $value, $exp['minlength'], $exp['maxlength'], $exp['char']);
				break;
		}
		return $result;
	}

	private function _parse_expression($expression) {
		
		$result = array('required' => FALSE, 'minlength' => NULL, 'maxlength' => NULL, 'min' => NULL, 'max' => NULL, 'exp' => 'string', 'char' => 'unicode');
		if (empty($expression)) return $result;
		if (is_array($expression))
			$result = _extends($expression, $result);
		else //如果不为数组，则解析表达式
		{
			$tmp = explode(',',$expression);
			$required_list = array(1 => TRUE,0 => FALSE,2 => Validate::SUB_NO_ZERO);
			$result['required'] = isset($required_list[($tmp[0])]) ? $required_list[($tmp[0])] : TRUE;
			$result['exp'] = !empty($tmp[1]) ? str_replace('&comma;',',',$tmp[1]) : 'string';
			$result['char'] = isset($tmp[4]) && $tmp[4] == 'a' ? 'ansi' : 'unicode';

			$pos_min = isset($tmp[2]) ? strpos($tmp[2],'v') : FALSE;
			$pos_max = isset($tmp[3]) ? strpos($tmp[3],'v') : FALSE;
			$result['minlength'] = (isset($tmp[2]) && $pos_min === FALSE) ? intval($tmp[2]) : NULL;
			$result['maxlength'] = (isset($tmp[3]) && $pos_max === FALSE) ? intval($tmp[3]) : NULL;
			$result['min'] = (isset($tmp[2]) && $pos_min !== FALSE) ? substr($tmp[2],$pos_min + 1) + 0 : NULL;
			$result['max'] = (isset($tmp[3]) && $pos_max !== FALSE) ? substr($tmp[3],$pos_max + 1) + 0 : NULL;
		}	
		return $result;
	}

	private function _check_string($value, $minlength = NULL, $maxlength = NULL, $char = 'ansi')
	{
		$value = strval($value);
		$result = $this->_check_length($value, $minlength, $maxlength, $char);
		if ($result != Validate::SUB_OK) return $result;
		return $this->_check_banned($value);
	}

	private function _check_banned($value)
	{
		if (strlen($value) >= 3) { //为减少检查压力,要求至少1个汉字(或3个英文)
			$banned = $this->_censor($value);
			if (!empty($banned)) return Validate::SUB_BANNED;
		}
		return Validate::SUB_OK;
	}

	private function _check_number($value, $min = NULL, $max = NULL, $minlength = NULL, $maxlength = NULL)
	{
		if (is_numeric($value)) {
		
			if (!is_null($minlength) || !is_null($maxlength)) //测试长度，直接当做字符串处理
				return $this->_check_string($value, $minlength, $maxlength, 'unicode');

			if (is_null($max)) { 
				if ($min !== NULL) //必须大于等于$min
					return $value >= $min ? Validate::SUB_OK : Validate::SUB_RAN;
			} else {
				return $value >= $min && $value <= $max ? Validate::SUB_OK : Validate::SUB_RAN;
			}
		} else
			return Validate::SUB_EXP;
		return Validate::SUB_OK;
	}

	private function _check_length($value, $minlength, $maxlength, $char = 'ansi')
	{
		$length = strlen_ansi($value, Kohana::$charset, $char == 'ansi' ? 2 : 1);
		return $this->_check_number($length, $minlength, $maxlength) != Validate::SUB_OK ? Validate::SUB_LEN : Validate::SUB_OK;
	}

	private function _check_bool($value, $required) 
	{
		if (!$required) return Validate::SUB_OK; // 如果非必填,一律返回OK

		return is_bool($value) ? Validate::SUB_OK : Validate::SUB_EXP; 
	}
	
	private function _check_regexp($regexp, $value, $minlength, $maxlength, $char = 'unicode')
	{
		//echo '/^'.$regexp.'$/iu';
		$regexp = strpos($regexp, '/') === 0 ? $regexp : '/^'.$regexp.'$/iu';
		if (preg_match($regexp, $value) == 1)
			return $this->_check_string($value, $minlength, $maxlength, $char);
		else
			return Validate::SUB_EXP;
	}

	private function _check_email($value, $minlength, $maxlength)
	{
		return $this->_check_regexp($this->_patterns['email'], $value, $minlength, $maxlength);
	}

	private function _check_url($value, $minlength, $maxlength)
	{
		return $this->_check_regexp($this->_patterns['url'], $value, $minlength, $maxlength); //不允许出现非英文字符
	}

	private function _check_datetime($value)
	{
		return $this->_check_regexp($this->_patterns['datetime'], $date, 14, 19); 
	}

	private function _check_date($value)
	{
		return $this->_check_regexp($this->_patterns['date'], $date, 8, 10);
	}

	private function _check_time($value)
	{
		return $this->_check_regexp($this->_patterns['time'], $date, 5, 8); 
	}

	private function _check_type($key, $value)
	{
		$type_ids = $this->_get_fields_list($key);
		if (empty($type_ids)) //此类别不存在
			return Validate::SUB_EXP;
		else
			return array_key_exists($value,$type_ids) ? Validate::SUB_OK : Validate::SUB_EXP;
	}

	private function _check_data($value, $data)
	{
		return in_array($value,$data) ? Validate::SUB_OK : Validate::SUB_EXP;
	}
	
	abstract protected function _get_fields_list($key);
	
	abstract protected function _censor($key);
	
	private function _get_error($_check, $line, $text2 = '')
	{
		$exp = $line['verify'];
		$error = Kohana::message('validate','error.'.(!empty($line['message']) ? 'DIY' : $_check ));
		return array(
			'message' => $error,
			'fields' => array(
				':type' => $_check,
				':text' => $line['text'],
				':text1' => $line['text'],
				':text2' => $text2,
				':message' => $line['message'],
				':min' => $exp['min'],
				':max' => $exp['max'],
				':minlength' => $exp['minlength'],
				':maxlength' => $exp['maxlength'],
			),
		);
	}

	private function _get_tips($message_key, $line)
	{
		$exp = $line['verify'];

		$tips = $line['message']; //如果有此字段的消息，则调取
		if (empty($tips)) return NULL;
		/*
		if (empty($tips)) //不然，调取默认信息
		{
			$postfix = '';
			if ($line['multi'])
			{
				$postfix = 'multi';
			}
			else
			{
				$postfix = $exp['ansi'] ? 'ansi' : 'string';
				if(!is_null($exp['min']) || !is_null($exp['max']))
				{
					switch ($exp['exp']) {
						case 'timestamp':
							!is_null($exp['min']) && $exp['min'] = date('Y-m-d H:i:s', $exp['min']);
							!is_null($exp['max']) && $exp['max'] = date('Y-m-d H:i:s', $exp['max']);
							break;
						case 'timetick':
							!is_null($exp['min']) && $exp['min'] = date('H:i:s', timetick_to_timestamp($exp['min']));
							!is_null($exp['max']) && $exp['max'] = date('H:i:s', timetick_to_timestamp($exp['max']));
							break;
						case 'daytick':
							!is_null($exp['min']) && $exp['min'] = date('H:i:s', daytick_to_timestamp($exp['min']));
							!is_null($exp['max']) && $exp['max'] = date('H:i:s', daytick_to_timestamp($exp['max']));
							break;
						default:
							break;
					}
				}
			}
			if(!is_null($exp['min']) && !is_null($exp['max']))
				$postfix .= '_range';
			elseif(!is_null($exp['min']))
				$postfix .= '_set';
			elseif(!is_null($exp['min']) && !is_null($exp['max']))
				$postfix .= '_len_range';
			elseif(!is_null($exp['min']))
				$postfix .= '_len_set';

			$tips = Kohana::message('validate', 'tips.'.$postfix);
		}
		*/
		return array(
			'message' => $tips,
			'fields' => array(
				':text' => $line['text'],
				':minlength' => $exp['minlength'],
				':maxlength' => $exp['maxlength'],
				':min' => $exp['min'],
				':max' => $exp['max'],
			),
		);
	}
	
}